[理解Underscore和Lo-Dash] Collections _.each

_.each

遍历集合,对集合中的每个元素执行回调。

API

Lo-Dash

_.forEach(collection [, callback=identity, thisArg])

Aliases

each

Arguments

  1. collection (Array|Object|String): 要遍历的集合
  2. [callback=identity] (Function): 每次迭代中调用的函数
  3. [thisArg] (任意): 绑定到callbackthis
  4. callback接受三个参数: (value, index|key, collection)

Returns

(Array, Object, String): 返回collection.

Underscore

_.each(list, iterator, [context])

Aliases

forEach

Arguments

  1. list (Array|Object|String): 要遍历的集合
  2. iterator (Function): 每次迭代中调用的函数
  3. [context] (任意): 绑定到callbackthis
  4. iterator接受三个参数: (element|value, index|key, list)

Returns

(Array, Object, String): 返回undefined.

Note

  • Lo-Dash可以省略回调函数,而Underscore则必须传入
  • Lo-Dash可以通过在回调中返回false提前结束迭代
  • Lo-Dash会返回Collection从而允许链式操作,Underscore的返回值则是undefined

Example

Lo-Dash

1
2
3
4
5
6
7
8
_.forEach([1,2,3])
// => 返回[1,2,3]

_([1, 2, 3]).forEach(alert).join(',');
// => alert每个数字并返回'1,2,3'

_.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
// => alert每个数字value(不保证按照定义的顺序执行)

Underscore

1
2
3
4
_.each([1, 2, 3], alert);
// => alert每个数字
_.each({one : 1, two : 2, three : 3}, alert);
// => alert每个数字value(不保证按照定义的顺序执行)

Source

Lo-Dash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function forEach(collection, callback, thisArg) {
    var index = -1,
    length = collection ? collection.length : 0;

    callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg);
    if (typeof length == 'number') {
        while (++index < length) {
            if (callback(collection[index], index, collection) === false) {
                break;
            }
        }
    } else {
        forOwn(collection, callback);
    }
    return collection;
}

Underscore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var each = _.each = _.forEach = function(obj, iterator, context) {
    if (obj == null) return;
    if (nativeForEach && obj.forEach === nativeForEach) {
      obj.forEach(iterator, context);
    } else if (obj.length === +obj.length) {
      for (var i = 0, l = obj.length; i < l; i++) {
        if (iterator.call(context, obj[i], i, obj) === breaker) return;
      }
    } else {
      for (var key in obj) {
        if (_.has(obj, key)) {
          if (iterator.call(context, obj[key], key, obj) === breaker) return;
        }
      }
    }
  };

Additional

  • obj.length === +obj.length

+obj: 将obj转换成10进制数,否则返回NaN。因此,上面的判断等价于obj.length && typeof obj.length == 'number'

  • if (iterator.call(context, obj[i], i, obj) === breaker) return;

breaker是预先定义的空对象({}),Underscore内部用于提前结束循环的标志,并没有对外公开。另外,因为对象的===比较的是对象地址,所以就算用户在自己的iterator中返回{},上述if仍然不成立

  • for in循环不会遍历non-enumerable属性,因此像ObjecttoString等就不会被迭代